From 04559b620daa8590ad058becfdc7d4155b442afb Mon Sep 17 00:00:00 2001 From: "kfraser@localhost.localdomain" Date: Tue, 27 Mar 2007 18:51:07 +0100 Subject: [PATCH] hvm: Clean up intr_assist() functions (both VMX and SVM,. but mainly the latter!). Signed-off-by: Keir Fraser --- xen/arch/x86/hvm/svm/intr.c | 108 +++++++++++------------------ xen/arch/x86/hvm/svm/svm.c | 2 - xen/arch/x86/hvm/vmx/intr.c | 35 +++------- xen/include/asm-x86/hvm/svm/vmcb.h | 1 - 4 files changed, 50 insertions(+), 96 deletions(-) diff --git a/xen/arch/x86/hvm/svm/intr.c b/xen/arch/x86/hvm/svm/intr.c index ff7ea26e58..262f366838 100644 --- a/xen/arch/x86/hvm/svm/intr.c +++ b/xen/arch/x86/hvm/svm/intr.c @@ -64,88 +64,62 @@ asmlinkage void svm_intr_assist(void) { struct vcpu *v = current; struct vmcb_struct *vmcb = v->arch.hvm_svm.vmcb; - struct periodic_time *pt; int intr_type = APIC_DM_EXTINT; int intr_vector = -1; - int re_injecting = 0; - /* Check if an Injection is active */ - /* Previous Interrupt delivery caused this Intercept? */ + /* + * Previous Interrupt delivery caused this intercept? + * This will happen if the injection is latched by the processor (hence + * clearing vintr.fields.irq) but then subsequently a fault occurs (e.g., + * due to lack of shadow mapping of guest IDT or guest-kernel stack). + * + * NB. Exceptions that fault during delivery are lost. This needs to be + * fixed but we'll usually get away with it since faults are usually + * idempotent. But this isn't the case for e.g. software interrupts! + */ if ( vmcb->exitintinfo.fields.v && (vmcb->exitintinfo.fields.type == 0) ) { - v->arch.hvm_svm.saved_irq_vector = vmcb->exitintinfo.fields.vector; + intr_vector = vmcb->exitintinfo.fields.vector; vmcb->exitintinfo.bytes = 0; - re_injecting = 1; + HVMTRACE_1D(REINJ_VIRQ, v, intr_vector); + svm_inject_extint(v, intr_vector); + return; } - /* Previous interrupt still pending? */ + /* + * Previous interrupt still pending? This occurs if we return from VMRUN + * very early in the entry-to-guest process. Usually this is because an + * external physical interrupt was pending when we executed VMRUN. + */ if ( vmcb->vintr.fields.irq ) - { - intr_vector = vmcb->vintr.fields.vector; - vmcb->vintr.bytes = 0; - re_injecting = 1; - } - /* Pending IRQ saved at last VMExit? */ - else if ( v->arch.hvm_svm.saved_irq_vector >= 0 ) - { - intr_vector = v->arch.hvm_svm.saved_irq_vector; - v->arch.hvm_svm.saved_irq_vector = -1; - re_injecting = 1; - } - /* Now let's check for newer interrrupts */ - else - { - pt_update_irq(v); - - hvm_set_callback_irq_level(); - - if ( cpu_has_pending_irq(v) ) - { - /* - * Create a 'fake' virtual interrupt on to intercept as soon - * as the guest _can_ take interrupts. Do not obtain the next - * interrupt from the vlapic/pic if unable to inject. - */ - if ( irq_masked(vmcb->rflags) || vmcb->interrupt_shadow ) - { - vmcb->general1_intercepts |= GENERAL1_INTERCEPT_VINTR; - HVMTRACE_2D(INJ_VIRQ, v, 0x0, /*fake=*/ 1); - svm_inject_extint(v, 0x0); /* actual vector doesn't really matter */ - return; - } - intr_vector = cpu_get_interrupt(v, &intr_type); - } - } + return; - /* have we got an interrupt to inject? */ - if ( intr_vector < 0 ) + /* Crank the handle on interrupt state and check for new interrrupts. */ + pt_update_irq(v); + hvm_set_callback_irq_level(); + if ( !cpu_has_pending_irq(v) ) return; - switch ( intr_type ) + /* + * Create a 'fake' virtual interrupt on to intercept as soon as the + * guest _can_ take interrupts. Do not obtain the next interrupt from + * the vlapic/pic if unable to inject. + */ + if ( irq_masked(vmcb->rflags) || vmcb->interrupt_shadow ) { - case APIC_DM_EXTINT: - case APIC_DM_FIXED: - case APIC_DM_LOWEST: - /* Re-injecting a PIT interruptt? */ - if ( re_injecting && (pt = is_pt_irq(v, intr_vector, intr_type)) ) - ++pt->pending_intr_nr; - /* let's inject this interrupt */ - if (re_injecting) - HVMTRACE_1D(REINJ_VIRQ, v, intr_vector); - else - HVMTRACE_2D(INJ_VIRQ, v, intr_vector, /*fake=*/ 0); - svm_inject_extint(v, intr_vector); - break; - case APIC_DM_SMI: - case APIC_DM_NMI: - case APIC_DM_INIT: - case APIC_DM_STARTUP: - default: - printk("Unsupported interrupt type: %d\n", intr_type); - BUG(); - break; + vmcb->general1_intercepts |= GENERAL1_INTERCEPT_VINTR; + HVMTRACE_2D(INJ_VIRQ, v, 0x0, /*fake=*/ 1); + svm_inject_extint(v, 0x0); /* actual vector doesn't matter */ + return; } + /* Okay, we can deliver the interrupt: grab it and update PIC state. */ + intr_vector = cpu_get_interrupt(v, &intr_type); + BUG_ON(intr_vector < 0); + + HVMTRACE_2D(INJ_VIRQ, v, intr_vector, /*fake=*/ 0); + svm_inject_extint(v, intr_vector); + pt_intr_post(v, intr_vector, intr_type); } diff --git a/xen/arch/x86/hvm/svm/svm.c b/xen/arch/x86/hvm/svm/svm.c index a7b1046de7..ba799d27be 100644 --- a/xen/arch/x86/hvm/svm/svm.c +++ b/xen/arch/x86/hvm/svm/svm.c @@ -963,8 +963,6 @@ static int svm_vcpu_initialise(struct vcpu *v) v->arch.ctxt_switch_from = svm_ctxt_switch_from; v->arch.ctxt_switch_to = svm_ctxt_switch_to; - v->arch.hvm_svm.saved_irq_vector = -1; - v->arch.hvm_svm.launch_core = -1; if ( (rc = svm_create_vmcb(v)) != 0 ) diff --git a/xen/arch/x86/hvm/vmx/intr.c b/xen/arch/x86/hvm/vmx/intr.c index 8c0dc81a1c..73487efa9e 100644 --- a/xen/arch/x86/hvm/vmx/intr.c +++ b/xen/arch/x86/hvm/vmx/intr.c @@ -89,7 +89,7 @@ static void update_tpr_threshold(struct vlapic *vlapic) asmlinkage void vmx_intr_assist(void) { int intr_type = 0; - int highest_vector; + int intr_vector; unsigned long eflags; struct vcpu *v = current; unsigned int idtv_info_field; @@ -106,8 +106,9 @@ asmlinkage void vmx_intr_assist(void) if ( unlikely(v->arch.hvm_vmx.vector_injected) ) { - v->arch.hvm_vmx.vector_injected=0; - if (unlikely(has_ext_irq)) enable_irq_window(v); + v->arch.hvm_vmx.vector_injected = 0; + if ( unlikely(has_ext_irq) ) + enable_irq_window(v); return; } @@ -132,7 +133,6 @@ asmlinkage void vmx_intr_assist(void) enable_irq_window(v); HVM_DBG_LOG(DBG_LEVEL_1, "idtv_info_field=%x", idtv_info_field); - return; } @@ -154,30 +154,13 @@ asmlinkage void vmx_intr_assist(void) return; } - highest_vector = cpu_get_interrupt(v, &intr_type); - if ( highest_vector < 0 ) - return; + intr_vector = cpu_get_interrupt(v, &intr_type); + BUG_ON(intr_vector < 0); - switch ( intr_type ) - { - case APIC_DM_EXTINT: - case APIC_DM_FIXED: - case APIC_DM_LOWEST: - HVMTRACE_2D(INJ_VIRQ, v, highest_vector, /*fake=*/ 0); - vmx_inject_extint(v, highest_vector, VMX_DELIVER_NO_ERROR_CODE); - break; - - case APIC_DM_SMI: - case APIC_DM_NMI: - case APIC_DM_INIT: - case APIC_DM_STARTUP: - default: - printk("Unsupported interrupt type\n"); - BUG(); - break; - } + HVMTRACE_2D(INJ_VIRQ, v, intr_vector, /*fake=*/ 0); + vmx_inject_extint(v, intr_vector, VMX_DELIVER_NO_ERROR_CODE); - pt_intr_post(v, highest_vector, intr_type); + pt_intr_post(v, intr_vector, intr_type); } /* diff --git a/xen/include/asm-x86/hvm/svm/vmcb.h b/xen/include/asm-x86/hvm/svm/vmcb.h index efedf27ae9..b709b17cbf 100644 --- a/xen/include/asm-x86/hvm/svm/vmcb.h +++ b/xen/include/asm-x86/hvm/svm/vmcb.h @@ -446,7 +446,6 @@ struct arch_svm_struct { u64 vmcb_pa; u32 *msrpm; u64 vmexit_tsc; /* tsc read at #VMEXIT. for TSC_OFFSET */ - int saved_irq_vector; int launch_core; unsigned long flags; /* VMCB flags */ -- 2.30.2